package com.bh.weapp.controller.common;

import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson2.JSONObject;
import com.bh.common.annotation.Log;
import com.bh.common.annotation.RepeatSubmit;
import com.bh.common.constant.Constants;
import com.bh.common.constant.SmsConstants;
import com.bh.common.constant.UserConstants;
import com.bh.common.core.controller.BaseController;
import com.bh.common.core.conver.SysUserConver;
import com.bh.common.core.domain.AjaxResult;
import com.bh.common.core.domain.entity.SysCustomerUser;
import com.bh.common.core.domain.entity.SysUser;
import com.bh.common.core.domain.model.LoginUser;
import com.bh.common.core.vo.*;
import com.bh.common.enums.BusinessType;
import com.bh.common.exception.ServiceException;
import com.bh.common.exception.base.BaseException;
import com.bh.common.utils.SecurityUtils;
import com.bh.common.utils.StringUtils;
import com.bh.common.utils.bean.BeanUtils;
import com.bh.common.utils.uuid.IdUtils;
import com.bh.common.utils.weapp.WeChatUtil;
import com.bh.extend.convert.JcCustomerConvert;
import com.bh.extend.domain.JcCustomerUser;
import com.bh.extend.service.IJcCustomerService;
import com.bh.extend.service.IJcCustomerUserService;
import com.bh.extend.vo.JcCustomerVo;
import com.bh.framework.manager.AsyncManager;
import com.bh.framework.manager.factory.AsyncFactory;
import com.bh.framework.web.service.SysLoginService;
import com.bh.framework.web.service.TokenService;
import com.bh.system.service.ISysCustomerUserService;
import com.bh.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;


/**
 * 登录验证
 *
 * @author ruo-yi
 */
@Transactional(rollbackFor = Exception.class)
@Slf4j
@Api(tags = {"COMMON登录接口"})
@RestController
@RequestMapping("/api/common")
public class SysLoginApiController extends BaseController {

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysCustomerUserService sysCustomerUserService;

    @Autowired
    private IJcCustomerUserService jcCustomerUserService;

    @Autowired
    private IJcCustomerService jcCustomerService;

    @Autowired
    private JcCustomerConvert jcCustomerConvert;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private SysLoginService sysLoginService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysUserConver sysUserConver;


    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "登录名称", dataType = "String", required = true, dataTypeClass = String.class),
            @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @ApiOperation("登录")
    @PostMapping("/jwt/login")
    public AjaxResult jwtLogin(@RequestBody WeappLoginUserVo userVo) {
        //先直接查询用户电话号码
        SysUser phoneUser = sysUserService.selectUserByPhoneNumber(userVo.getUsername());
        if (phoneUser != null) {
            userVo.setUsername(phoneUser.getUserName());
        }
        // 登录前置校验
        String token = sysLoginService.weappLogin(userVo.getUsername(), userVo.getPassword());
        Map<String, Object> datas = new HashMap<>();
        if (token != null) {
            SysUser user = userService.selectUserByUserName(userVo.getUsername());
            datas = this.getUserInfo(user);
        }
        return AjaxResult.success("登录成功,请妥善保管您的token信息").put("token", token).put("user", datas);
    }


    @Transactional(rollbackFor = Exception.class)
    @ApiImplicitParam(name = "code", value = "微信CODE", dataType = "String", dataTypeClass = String.class)
    @ApiOperation(value = "微信端登录", notes = "微信端登录")
    @PostMapping("/wechatLogin")
    public AjaxResult wechatLogin(@RequestBody @Validated WechatLoginUserVo userVo) {
        JSONObject result = WeChatUtil.getOpenid(userVo.getCode());
        if (result == null) {
            throw new BaseException("获取用户openid错误！");
        }
        if (result.get("openid") == null) {
            return error("获取用户openid错误！");
        }
        String openId = result.get("openid").toString();
        //外部用户或者内部用户都可以
        String password = "SDFrvs.5677!";
        // 通过 openId 获取用户名，因此不需要再次比对
        SysUser user = userService.selectUserByOpenid(openId);
        if (user == null) {
            if (StringUtils.isBlank(userVo.getPhonenumber())) {
                return error("用户未注册，请提交注册资料!");
            }
            // 直接进行注册或关联内部员工
            user = userService.selectUserByPhoneNumber(userVo.getPhonenumber());
            if (user == null) {
                // 直接进行注册
                SysCustomerUserVo customerUserVo = new SysCustomerUserVo();
                customerUserVo.setPhonenumber(userVo.getPhonenumber());
                customerUserVo.setNickName(userVo.getNickName());
                customerUserVo.setAvatar(userVo.getAvatar());
                customerUserVo.setSex(userVo.getSex());
                customerUserVo.setOpenId(openId);
                SysCustomerUser customerUser = registerWeappUser(customerUserVo, password);
                user = userService.selectUserById(customerUser.getUserId());
            } else {
                // 关联内部员工
                user.setOpenId(openId);
                user.setAvatar(userVo.getAvatar());
                user.setSex(userVo.getSex());
                userService.updateUser(user);
            }
        }
        String token = sysLoginService.weappLogin(user.getUserName(), null);
        Map<String, Object> datas = new HashMap<>();
        if (token != null) {
            datas = this.getUserInfo(user);
        }
        return AjaxResult.success("登录成功,请妥善保管您的token信息").put("token", token).put("user", datas);
    }


    /**
     * 校验用户名
     */
    @RepeatSubmit
    @ApiOperation("校验电话号码以及绑定状态")
    @PostMapping("/getPhoneNumberAndBindFlag")
    public AjaxResult getPhoneNumberAndBindFlag(@RequestParam("phoneCode") String phoneCode) {
        String phonenumber = WeChatUtil.getPhoneNumber(phoneCode);
        if (StringUtils.isBlank(phonenumber)) {
            throw new BaseException("获取用户电话号码错误！");
        }
        SysUser user = userService.selectUserByPhoneNumber(phonenumber);
        return AjaxResult.success("获取电话号码成功").put("phonenumber", phonenumber).put("bindFlag", user != null);
    }


    /**
     * 校验用户名
     */
    @RepeatSubmit
    @ApiImplicitParam(name = "loginName", value = "用户名", dataType = "String", dataTypeClass = String.class)
    @ApiOperation("校验用户名")
    @PostMapping("/checkUserNameUnique")
    public AjaxResult checkUserNameUnique(@RequestBody SysUserCheckVo userVo) {
        SysUser user = sysUserConver.toDO(userVo);
        return AjaxResult.success(userService.checkUserNameUnique(user));
    }

    /**
     * 校验手机号码
     */
    @RepeatSubmit
    @ApiImplicitParam(name = "phonenumber", value = "手机号码", dataType = "String", dataTypeClass = String.class)
    @ApiOperation("校验手机号码")
    @PostMapping("/checkPhoneUnique")
    public AjaxResult checkPhoneUnique(@RequestBody SysUserCheckVo userVo) {
        SysUser user = sysUserConver.toDO(userVo);
        return AjaxResult.success(userService.checkPhoneUnique(user));
    }


    @RepeatSubmit
    @ApiOperation("API重置密码")
    @Log(title = "API重置密码", businessType = BusinessType.UPDATE)
    @PostMapping("/resetPwd")
    public AjaxResult resetPwdSave(String oldPassword, String newPassword) {
        LoginUser loginUser = getLoginUser();
        // 检测密码复杂度，必须为 6-20位，且包含字母、数字、符号
        if (!ReUtil.isMatch(Constants.REGEXP, newPassword)) {
            return error("密码必须包含大写字母 、数字、 特殊字符（四种里至少三种，且至少6位）");
        }
        String userName = loginUser.getUsername();
        String password = sysUserService.selectUserByUserName(userName).getPassword();
        if (!SecurityUtils.matchesPassword(oldPassword, password)) {
            return error("修改密码失败，旧密码错误");
        }
        if (SecurityUtils.matchesPassword(newPassword, password)) {
            return error("新密码不能与旧密码相同");
        }
        newPassword = SecurityUtils.encryptPassword(newPassword);
        if (userService.resetUserPwd(userName, newPassword) > 0) {
            // 更新缓存用户密码
            loginUser.getUser().setPassword(newPassword);
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("修改密码异常，请联系管理员");
    }


    /**
     * 修改保存用户
     */
    @Transactional(rollbackFor = Exception.class)
    @RepeatSubmit
    @ApiOperation("修改保存用户")
    @Log(title = "API用户管理", businessType = BusinessType.UPDATE)
    @PostMapping("/editUserSave")
    public AjaxResult editUserSave(@RequestBody @Validated UserVo userVo) {
        LoginUser loginUser = getLoginUser();
        SysUser sysUser = loginUser.getUser();
        BeanUtils.copyBeanProp(userVo, SysUser.class);
        SysUser user = new SysUser();
        user.setUserName(sysUser.getUserName());
        user.setUserId(getUserId());
        if (!userService.checkUserNameUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败，手机号码已存在");
        }
        user.setUserId(sysUser.getUserId());
        user.setPassword(null);
        user.setAvatar(null);
        user.setDeptId(null);
        if (userService.updateUserProfile(user) > 0) {
            // 更新缓存用户信息
            sysUser.setNickName(user.getNickName());
            sysUser.setPhonenumber(user.getPhonenumber());
            sysUser.setSex(user.getSex());
            tokenService.setLoginUser(loginUser);
            return success();
        }
        return error("修改个人信息异常，请联系管理员");
    }


    /**
     * 根据用户编号获取详细信息
     */
    @ApiOperation("根据用户编号获取详细信息")
    @GetMapping({"/getUserInfo", "/getUserInfo/{userId}"})
    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) {
        if (userId == null) {
            userId = getUserId();
        }
        SysUser user = userService.selectUserById(userId);
        Map<String, Object> datas = this.getUserInfo(user);
        return AjaxResult.success(datas);
    }

    private Map<String, Object> getUserInfo(SysUser user) {
        Map<String, Object> datas = new HashMap<>();
        if (user.getUserType().equals(UserConstants.REGISTER_USER_TYPE)) {
            SysCustomerUser customerUser = sysCustomerUserService.selectUserById(user.getUserId());
            datas.put("customerUser", customerUser);
            JcCustomerUser jcCustomerUser = jcCustomerUserService.selectJcCustomerUserByUserId(user.getUserId());
            if (jcCustomerUser != null) {
                customerUser.setCustomerId(jcCustomerUser.getCustomerId());
                JcCustomerVo customer = jcCustomerConvert.toVo(jcCustomerService.selectJcCustomerById(jcCustomerUser.getCustomerId()));
                datas.put("customer", customer);
            }
        } else {
            datas.put("sysUser", user);
        }
        return datas;
    }

    private SysCustomerUser registerWeappUser(SysCustomerUserVo customerUserVo, String pwd) {
        SysCustomerUser user = sysUserConver.toDO(customerUserVo);
        if (StringUtils.isNotBlank(user.getUserName()) && !sysCustomerUserService.checkUserNameUnique(user)) {
            throw new ServiceException("新增用户'" + user.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !sysCustomerUserService.checkPhoneUnique(user)) {
            throw new ServiceException("新增用户'" + user.getUserName() + "'失败，手机号码已存在");
        }
        if (StringUtils.isBlank(user.getUserName())) {
            user.setUserName(user.getPhonenumber());
        }
        if (StringUtils.isBlank(user.getPassword())) {
            user.setPassword(IdUtils.getRandomPwd());
        }
        user.setUserName(user.getPhonenumber());
        // 发送短信
        user.setPassword(SecurityUtils.encryptPassword(pwd));
        user.setCreateBy(user.getUserName());
        int num = sysCustomerUserService.insertUser(user);
        if (num > 0) {
            Map<String, String> map = new HashMap<>();
            map.put("name", user.getNickName());
            map.put("pwd", pwd);
            AsyncManager.me().execute(AsyncFactory.pushSms(user.getPhonenumber(), map, SmsConstants.CACHE_TEMPLATE_CODE_4));
        }
        return user;
    }
}
